/* OLA WIFI device Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_heap_caps.h"

#include "ola.h"
#include "ola_softap.h"
#include "ola_coap.h"


// extern "C" void app_main()

void monitor_cpu_memory(void)
{
    static uint32_t mem_last = 0;
    uint32_t mem_current;

    mem_current = xPortGetFreeHeapSize();
    if(mem_current != mem_last)
    {
        printf("mem_last = %d,  mem_current = %d, heap_caps_get_largest_free_block() = %d\n", 
            mem_last, 
            mem_current,
            heap_caps_get_largest_free_block(MALLOC_CAP_8BIT)
        );
        mem_last = mem_current;
        // heap_caps_print_heap_info(MALLOC_CAP_8BIT);
    }
}

void esp32_gpio_config(void)
{
    gpio_config_t io;
    
    printf("Config gpio 25 & 26 & 27");
    memset(&io, 0, sizeof(io));
    io.intr_type = GPIO_PIN_INTR_DISABLE;
    io.mode = GPIO_MODE_OUTPUT;
    io.pin_bit_mask = (1UL << 25) | (1UL << 26) | (1UL << 27);
    io.pull_down_en = 0;
    io.pull_up_en = 0;
    gpio_config(&io);
}

static void ola_connect_wifi(void)
{
	nvs_handle fd;
    char ssid[50], pwd[50];
    size_t size = 0;

	if (nvs_open("OLA", NVS_READONLY, &fd) == ESP_OK) {        
		size = sizeof(ssid);
	    if (nvs_get_str(fd,"ssid", ssid, &size) != ESP_OK) {
		    printf("--get ssid fail\n");
            return;
		}
        printf("--get ssid: %s\n", ssid);
		
		size = sizeof(pwd);
	    if (nvs_get_str(fd,"pwd", pwd, &size) != ESP_OK) {
		    printf("--get pwd fail\n");
            return;
		}
        printf("--get pwd: %s\n", pwd);
        nvs_close(fd);
        ola_pal_softap_connect_wifi_router(ssid, pwd);
    }
    else
    {
        printf("--get OLA wifi parameter failed\n");
    }
    
}

static void ola_reset_factory(void)
{
	nvs_handle fd;

	if (nvs_open("OLA", NVS_READWRITE, &fd) == ESP_OK) {        
        if (nvs_set_str(fd, "feedid", "") != ESP_OK) { 
            printf("--ola_reset_factory feedid fail\n"); 
        } else {
            printf("--ola_reset_factory feedid succeed: 0\n"); 
        }
        nvs_close(fd);
    }
    else
    {
        printf("--ola_reset_factory failed\n");
    }
    
}

void ola_task_wifi_monitor(void *param)
{
    int count, retry_count, retry_init;
    
    printf("--ola_task_wifi_monitor in\n");

    retry_count = 0;
    retry_init = 0;
    count = 0;
    while (1)
    {
        monitor_cpu_memory();
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        if(count++ < 60)
        {
            if(count % 10 == 0)
            {
                retry_count++;
                esp_wifi_disconnect();
                esp_wifi_connect();
                printf("--Retry to connect AP, retry_count = %d\n", retry_count);
            }
        }
        else
        {
            retry_init++;
            ola_connect_wifi();
            count = 0;
            printf("--Retry to init wifi, retry_init = %d\n", retry_init);
        }
        
    }
    

}

void ola_task(void * param)
{
    // step1 enter ap mod
    extern int ola_pal_softap_enter_ap_mode(void);
    if (0 != ola_pal_softap_enter_ap_mode()) {
        printf("Enter softAP mode failed\r\n");
    }

    // step 2 softap main loop
    extern int ola_softap_start(unsigned int timeout_ms);
    if (0 != ola_softap_start(60000)) {
        printf("ola_softap_start failed\r\n");
        ola_connect_wifi();
    }
    else
    {
       ola_reset_factory();
    }

    //start coap server
    xTaskCreate(coap_example_server, "coap", 8 * 1024, NULL, 5, NULL);

    TaskHandle_t handle;
    xTaskCreate(ola_task_wifi_monitor, "ola_task_wifi_monitor", 4*1024, NULL, 2, &handle);
    
    printf("ola_softap_start finished, enter next loop\r\n");
    
    // test gethostbyname
    for (int i = 5; i >= 0; i--) {
        printf("test gethostbyname in %d seconds...\n", i);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    // extern int ola_pal_gethostbyname(char *hostname, char *ip_buff, unsigned int buff_len);
    // char ip_buff[20] = {0};
    // printf("ola_pal_gethostbyname ret = %d\r\n", ola_pal_gethostbyname("www.baidu.com", ip_buff, 15));
    
    // step 3 OLA main protocal
    extern int ola_main_start();
    ola_main_start();

    printf("ola_main_start finished !!\r\n");

    /**************************************************************************************/

}

void app_main()
{
    printf("Hello world-!\n");

    /* Print chip information */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ",
            chip_info.cores,
            (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
            (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");

    printf("silicon revision %d, ", chip_info.revision);

    printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
            (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
    
    esp32_gpio_config();

    TaskHandle_t handle;
    xTaskCreate(ola_task, "ola_task", 20*1024, NULL, 2, &handle);
    while (1) {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        continue;
    }
	// return (ola_thread_t)handle;

    for (int i = 10; i >= 0; i--) {
        printf("Restarting in %d seconds...\n", i);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    printf("Restarting now.\n");
    fflush(stdout);
    esp_restart();
}
